package observers;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static observers.LoggerObserver.TIMESTAMP_FORMATTER;

public class StatsObserver implements Observer{
    private static StatsObserver instance;
    private final Map<String, Duration> fileDurations;
    private final Map<String, LocalDateTime> fileStartTimes;
    private String currentFile = null;
    private static final String STATS_FILE = "stats.txt";
    private String sessionStartTime;

    private StatsObserver() {
        this.fileDurations = new HashMap<>();
        this.fileStartTimes = new HashMap<>();
    }

    public static StatsObserver getInstance() {
        if (instance == null) {
            instance = new StatsObserver();
        }
        return instance;
    }


    public void startTracking(String filename) {
        if(currentFile == null || !currentFile.equals(filename)){
            stopTracking(currentFile);
        }
        fileStartTimes.put(filename, LocalDateTime.now());
        currentFile = filename;
    }

    public void stopTracking(String filename) {
        LocalDateTime startTime = fileStartTimes.remove(filename);
        if (startTime != null) {
            Duration currentDuration = Duration.between(startTime, LocalDateTime.now());
            fileDurations.compute(filename, (key, oldDuration) ->
                    oldDuration == null ? currentDuration : oldDuration.plus(currentDuration)
            );
        }
        currentFile = null;
    }

    private static String formatDuration(Duration duration) {
        long seconds = duration.getSeconds() % 60;
        long minutes = duration.toMinutes();
        long hours = minutes / 60;
        long remainingMinutes = minutes % 60;
        long days = hours / 24;
        long remainingHours = hours % 24;

        StringBuilder builder = new StringBuilder();
        if (days > 0) {
            builder.append(days).append("天 ");
        }
        if (remainingHours > 0) {
            builder.append(remainingHours).append("小时 ");
        }
        if (remainingMinutes > 0) {
            builder.append(remainingMinutes).append("分钟 ");
        }
        if (seconds > 0) {
            builder.append(seconds).append("秒");
        }

        return builder.toString();
    }

    public void printStats(String option) {
        System.out.println("Session start " + this.sessionStartTime);
        if ("all".equals(option)) {
            if(currentFile != null){
                String tmp = currentFile;
                stopTracking(currentFile);
                startTracking(tmp);
            }

            for (Map.Entry<String, Duration> entry : fileDurations.entrySet()) {
                System.out.println("./" + entry.getKey() + " " + formatDuration(entry.getValue()));
            }
        } else if ("current".equals(option)) {
            if (currentFile != null) {
                Duration currentDuration = fileDurations.getOrDefault(currentFile, Duration.ZERO);
                if (fileStartTimes.containsKey(currentFile)) {
                    currentDuration = currentDuration.plus(Duration.between(fileStartTimes.get(currentFile), LocalDateTime.now()));
                }
                System.out.println("Current file: ./" + currentFile + " " + formatDuration(currentDuration));
            }
        }
    }

    public void statsSave() {
        Path p = Paths.get(STATS_FILE);
        stopTracking(currentFile);
        try {
            String existingContent = "";
            if (Files.exists(p)) {
                existingContent = new String(Files.readAllBytes(p), StandardCharsets.UTF_8);
            }
            StringBuilder content = new StringBuilder(existingContent);
            content.append("Session start ").append(this.sessionStartTime ).append('\n');

            for (Map.Entry<String, Duration> entry : fileDurations.entrySet()) {
                content.append("./").append(entry.getKey()).append(" ").append(formatDuration(entry.getValue())).append('\n');
            }
            Files.write(p, content.toString().getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void update(String message) {
        if (message == null) {
            LocalDateTime currentDateTime = LocalDateTime.now();
            this.sessionStartTime = currentDateTime.format(TIMESTAMP_FORMATTER);
        } else {
            String[] parts = message.split(" ", 2);
            String command = parts[0].toLowerCase();
            if(command.equals("exit")){
                statsSave();
            }
            else if(command.equals("load")){
                startTracking(parts[1]);
            }
            else if(command.equals("save")){
                stopTracking(currentFile);
            }
        }
    }
}
